home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Audio, Video & Photo / Songbird 0.7.0 / Songbird_0.7.0_windows-i686-msvc8.exe / components / sbDownloadDeviceHelper.js < prev    next >
Text File  |  2008-08-06  |  14KB  |  429 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. //
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. //
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. //
  13. // Software distributed under the License is distributed
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  15. // express or implied. See the GPL for the specific language
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc.,
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. // END SONGBIRD GPL
  24. //
  25. */
  26.  
  27. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  28. Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
  29. Components.utils.import("resource://app/jsmodules/ArrayConverter.jsm");
  30. Components.utils.import("resource://app/jsmodules/FolderUtils.jsm");
  31.  
  32. const Ci = Components.interfaces;
  33. const Cc = Components.classes;
  34. const Cr = Components.results;
  35. const Cu = Components.utils;
  36. const CE = Components.Exception;
  37.  
  38. const PREF_DOWNLOAD_MUSIC_FOLDER       = "songbird.download.music.folder";
  39. const PREF_DOWNLOAD_MUSIC_ALWAYSPROMPT = "songbird.download.music.alwaysPrompt";
  40.  
  41. /**
  42.  * \brief Get the name of the platform we are running on.
  43.  * \return The name of the OS platform. (ie. Windows).
  44.  * \retval Windows_NT Running under Windows.
  45.  * \retval Darwin Running under Darwin/OS X.
  46.  * \retval Linux Running under Linux.
  47.  * \retval SunOS Running under Solaris.
  48.  */
  49. function getPlatformString() 
  50. {
  51.   try {
  52.     var sysInfo =
  53.       Components.classes["@mozilla.org/system-info;1"]
  54.                 .getService(Components.interfaces.nsIPropertyBag2);
  55.     return sysInfo.getProperty("name");
  56.   }
  57.   catch (e) {
  58.     dump("System-info not available, trying the user agent string.\n");
  59.     var user_agent = navigator.userAgent;
  60.     if (user_agent.indexOf("Windows") != -1)
  61.       return "Windows_NT";
  62.     else if (user_agent.indexOf("Mac OS X") != -1)
  63.       return "Darwin";
  64.     else if (user_agent.indexOf("Linux") != -1)
  65.       return "Linux";
  66.     else if (user_agent.indexOf("SunOS") != -1)
  67.       return "SunOS";
  68.     return "";
  69.   }
  70. }
  71.  
  72. /**
  73.  * Our super-smart heuristic for determining if the download folder is valid.
  74.  */
  75. function folderIsValid(folder) {
  76.   try {
  77.     return folder && folder.isDirectory();
  78.   }
  79.   catch (e) {
  80.   }
  81.   return false;
  82. }
  83.  
  84. /**
  85.  * Returns an nsILocalFile or null if the path is bad.
  86.  */
  87. function makeFile(path) {
  88.   var file = Cc["@mozilla.org/file/local;1"].
  89.              createInstance(Ci.nsILocalFile);
  90.  
  91.   // Ensure all paths are lowercase for Windows.
  92.   // See bug #7178.
  93.   var actualPath = path;
  94.   if(getPlatformString() == "Windows_NT") {
  95.     actualPath = actualPath.toLowerCase();
  96.   }
  97.  
  98.   try {
  99.     file.initWithPath(actualPath);
  100.   }
  101.   catch (e) {
  102.     return null;
  103.   }
  104.   return file;
  105. }
  106.  
  107. /**
  108.  * Returns a file url for the path.
  109.  */
  110. function makeFileURL(path)
  111. {
  112.   // Can't use the IOService because we have callers off of the main thread...
  113.   // Super lame hack instead.
  114.  
  115.   // Ensure all paths are lowercase for Windows.
  116.   // See bug #7178.
  117.   var actualPath = path;
  118.   if(getPlatformString() == "Windows_NT") {
  119.     actualPath = actualPath.toLowerCase();
  120.   }
  121.   
  122.   return "file://" + actualPath;
  123. }
  124.  
  125. function sbDownloadDeviceHelper()
  126. {
  127.   this._mainLibrary = Cc["@songbirdnest.com/Songbird/library/Manager;1"]
  128.                         .getService(Ci.sbILibraryManager).mainLibrary;
  129. }
  130.  
  131. sbDownloadDeviceHelper.prototype =
  132. {
  133.   classDescription: "Songbird Download Device Helper",
  134.   classID:          Components.ID("{576b6833-15d8-483a-84d6-2fbd329c82e1}"),
  135.   contractID:       "@songbirdnest.com/Songbird/DownloadDeviceHelper;1",
  136.   QueryInterface:   XPCOMUtils.generateQI([Ci.sbIDownloadDeviceHelper])
  137. }
  138.  
  139. sbDownloadDeviceHelper.prototype.downloadItem =
  140. function sbDownloadDeviceHelper_downloadItem(aMediaItem)
  141. {
  142.   var downloadFileURL = this._safeDownloadFileURL();
  143.   if (!downloadFileURL) {
  144.     return;
  145.   }
  146.  
  147.   let uriArray           = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  148.                              .createInstance(Ci.nsIMutableArray);
  149.   let propertyArrayArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  150.                              .createInstance(Ci.nsIMutableArray);
  151.  
  152.   let item;
  153.   if (aMediaItem.library.equals(this._mainLibrary)) {
  154.     item = aMediaItem;
  155.   }
  156.   else {
  157.     this._addItemToArrays(aMediaItem, uriArray, propertyArrayArray);
  158.     let items = this._mainLibrary.batchCreateMediaItems(uriArray,
  159.                                                         propertyArrayArray,
  160.                                                         true);
  161.     item = items.queryElementAt(0, Ci.sbIMediaItem);
  162.   }
  163.  
  164.   this._setDownloadDestinationIfNotSet([item], downloadFileURL);
  165.   this._checkAndRemoveExistingItem(item);
  166.   this.getDownloadMediaList().add(item);
  167. }
  168.  
  169. sbDownloadDeviceHelper.prototype.downloadSome =
  170. function sbDownloadDeviceHelper_downloadSome(aMediaItems)
  171. {
  172.   var downloadFileURL = this._safeDownloadFileURL();
  173.   if (!downloadFileURL) {
  174.     return;
  175.   }
  176.  
  177.   let uriArray           = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  178.                              .createInstance(Ci.nsIMutableArray);
  179.   let propertyArrayArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  180.                              .createInstance(Ci.nsIMutableArray);
  181.  
  182.   var items = [];
  183.   while (aMediaItems.hasMoreElements()) {
  184.     let item = aMediaItems.getNext();
  185.     if (item.library.equals(this._mainLibrary)) {
  186.       items.push(item);
  187.     }
  188.     else {
  189.       this._checkAndRemoveExistingItem(item);
  190.       this._addItemToArrays(item, uriArray, propertyArrayArray);
  191.     }
  192.   }
  193.  
  194.   if (uriArray.length > 0) {
  195.     let addedItems = this._mainLibrary.batchCreateMediaItems(uriArray,
  196.                                                              propertyArrayArray,
  197.                                                              true);
  198.     for (let i = 0; i < addedItems.length; i++) {
  199.       items.push(addedItems.queryElementAt(i, Ci.sbIMediaItem));
  200.     }
  201.   }
  202.  
  203.   this._setDownloadDestinationIfNotSet(items, downloadFileURL);
  204.   this.getDownloadMediaList().addSome(ArrayConverter.enumerator(items));
  205. }
  206.  
  207. sbDownloadDeviceHelper.prototype.downloadAll =
  208. function sbDownloadDeviceHelper_downloadAll(aMediaList)
  209. {
  210.   var downloadFileURL = this._safeDownloadFileURL();
  211.   if (!downloadFileURL) {
  212.     return;
  213.   }
  214.  
  215.   let uriArray           = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  216.                              .createInstance(Ci.nsIMutableArray);
  217.   let propertyArrayArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  218.                              .createInstance(Ci.nsIMutableArray);
  219.  
  220.   var items = [];
  221.   var isForeign = aMediaList.library.equals(this._mainLibrary);
  222.   for (let i = 0; i < aMediaList.length; i++) {
  223.     var item = aMediaList.getItemByIndex(i);
  224.     if (isForeign) {
  225.       this._checkAndRemoveExistingItem(item);      
  226.       this._addItemToArrays(item, uriArray, propertyArrayArray);
  227.     }
  228.     else {
  229.       items.push(item);
  230.     }
  231.   }
  232.  
  233.   if (uriArray.length > 0) {
  234.     let addedItems = this._mainLibrary.batchCreateMediaItems(uriArray,
  235.                                                              propertyArrayArray,
  236.                                                              true);
  237.     for (let i = 0; i < addedItems.length; i++) {
  238.       items.push(addedItems.queryElementAt(i, Ci.sbIMediaItem));
  239.     }
  240.   }
  241.  
  242.   this._setDownloadDestinationIfNotSet(items, downloadFileURL);
  243.   this.getDownloadMediaList().addSome(ArrayConverter.enumerator(items));
  244. }
  245.  
  246. sbDownloadDeviceHelper.prototype.getDownloadMediaList =
  247. function sbDownloadDeviceHelper_getDownloadMediaList()
  248. {
  249.   if (!this._downloadDevice) {
  250.     var devMgr = Cc["@songbirdnest.com/Songbird/DeviceManager;1"]
  251.                    .getService(Ci.sbIDeviceManager);
  252.     if (devMgr) {
  253.       var downloadCat = "Songbird Download Device";
  254.       if (devMgr.hasDeviceForCategory(downloadCat)) {
  255.         this._downloadDevice = devMgr.getDeviceByCategory(downloadCat)
  256.                                      .QueryInterface(Ci.sbIDownloadDevice);
  257.       }
  258.     }
  259.   }
  260.   return this._downloadDevice ? this._downloadDevice.downloadMediaList : null;
  261. }
  262.  
  263. sbDownloadDeviceHelper.prototype.getDefaultMusicFolder =
  264. function sbDownloadDeviceHelper_getDefaultMusicFolder()
  265. {
  266.   var musicDir = FolderUtils.downloadFolder;
  267.   
  268.   if (!folderIsValid(musicDir)) {
  269.     // Great, default to the Desktop... This should work on all OS's.
  270.     musicDir = dirService.getFile("Desk", {});
  271.  
  272.     // We should never get something bad here, but just in case...
  273.     if (!folderIsValid(musicDir)) {
  274.       Cu.reportError("Desktop directory is not a directory!");
  275.       throw Cr.NS_ERROR_FILE_NOT_DIRECTORY;
  276.     }
  277.   }
  278.  
  279.   return musicDir;
  280. }
  281.  
  282. sbDownloadDeviceHelper.prototype.getDownloadFolder =
  283. function sbDownloadDeviceHelper_getDownloadFolder()
  284. {
  285.   const Application = Cc["@mozilla.org/fuel/application;1"].
  286.                       getService(Ci.fuelIApplication);
  287.   const prefs = Application.prefs;
  288.  
  289.   var downloadFolder;
  290.   if (prefs.has(PREF_DOWNLOAD_MUSIC_FOLDER)) {
  291.     var downloadPath = prefs.get(PREF_DOWNLOAD_MUSIC_FOLDER).value;
  292.     downloadFolder = makeFile(downloadPath);
  293.   }
  294.  
  295.   if (!folderIsValid(downloadFolder)) {
  296.     // The pref was either bad or empty. Use (and write) the default.
  297.     downloadFolder = this.getDefaultMusicFolder();
  298.     prefs.setValue(PREF_DOWNLOAD_MUSIC_FOLDER, downloadFolder.path);
  299.   }
  300.  
  301.   const alwaysPrompt = prefs.getValue(PREF_DOWNLOAD_MUSIC_ALWAYSPROMPT, false);
  302.   if (!alwaysPrompt) {
  303.     return downloadFolder;
  304.   }
  305.  
  306.   const sbs = Cc["@mozilla.org/intl/stringbundle;1"].
  307.               getService(Ci.nsIStringBundleService);
  308.   const strings =
  309.     sbs.createBundle("chrome://songbird/locale/songbird.properties");
  310.   const title =
  311.     strings.GetStringFromName("prefs.main.musicdownloads.chooseTitle");
  312.  
  313.   const wm = Cc["@mozilla.org/appshell/window-mediator;1"].
  314.              getService(Ci.nsIWindowMediator);
  315.   const mainWin = wm.getMostRecentWindow("Songbird:Main");
  316.  
  317.   // Need to prompt, launch the filepicker.
  318.   const folderPicker = Cc["@mozilla.org/filepicker;1"].
  319.                        createInstance(Ci.nsIFilePicker);
  320.   folderPicker.init(mainWin, title, Ci.nsIFilePicker.modeGetFolder);
  321.   folderPicker.displayDirectory = downloadFolder;
  322.  
  323.   if (folderPicker.show() != Ci.nsIFilePicker.returnOK) {
  324.     // This is our signal that the user cancelled the dialog. Some folks won't
  325.     // care, but most will.
  326.     throw new CE("User canceled the download dialog.", Cr.NS_ERROR_ABORT);
  327.   }
  328.  
  329.   downloadFolder = folderPicker.file;
  330.  
  331.   prefs.setValue(PREF_DOWNLOAD_MUSIC_FOLDER, downloadFolder.path);
  332.   return downloadFolder;
  333. }
  334.  
  335. sbDownloadDeviceHelper.prototype._checkAndRemoveExistingItem =
  336. function sbDownloadDeviceHelper__checkAndRemoveExistingItem(aMediaItem)
  337. {
  338.   var downloadMediaList = this.getDownloadMediaList();
  339.   if (downloadMediaList) {
  340.     var itemOriginUrl = aMediaItem.getProperty(SBProperties.originURL);
  341.  
  342.     var listEnumerationListener = {
  343.       onEnumerationBegin: function() {
  344.       },
  345.       onEnumeratedItem: function(list, item) {
  346.         downloadMediaList.remove(item);
  347.       },
  348.       onEnumerationEnd: function() {
  349.       },
  350.     };
  351.     
  352.     if ( (itemOriginUrl != "") &&
  353.          (itemOriginUrl != null) ) {
  354.       downloadMediaList.enumerateItemsByProperty(SBProperties.originURL,
  355.                                                  itemOriginUrl,
  356.                                                  listEnumerationListener);
  357.     }
  358.   }
  359. }
  360.  
  361. sbDownloadDeviceHelper.prototype._safeDownloadFileURL =
  362. function sbDownloadDeviceHelper__safeDownloadFileURL()
  363. {
  364.   // This function returns null if the user cancels the dialog.
  365.   try {
  366.     return makeFileURL(this.getDownloadFolder().path);
  367.   }
  368.   catch (e if e.result == Cr.NS_ERROR_ABORT) {
  369.   }
  370.   return "";
  371. }
  372.  
  373. sbDownloadDeviceHelper.prototype._addItemToArrays =
  374. function sbDownloadDeviceHelper__addItemToArrays(aMediaItem,
  375.                                                  aURIArray,
  376.                                                  aPropertyArrayArray)
  377. {
  378.   aURIArray.appendElement(aMediaItem.contentSrc, false);
  379.  
  380.   var dest   = SBProperties.createArray();
  381.   var source = aMediaItem.getProperties();
  382.   for (let i = 0; i < source.length; i++) {
  383.     var prop = source.getPropertyAt(i);
  384.     if (prop.id != SBProperties.contentSrc) {
  385.       dest.appendElement(prop, false);
  386.     }
  387.   }
  388.  
  389.   var target = aMediaItem.library.guid + "," + aMediaItem.guid;
  390.   dest.appendProperty(SBProperties.downloadStatusTarget, target);
  391.  
  392.   aPropertyArrayArray.appendElement(dest, false);
  393. }
  394.  
  395. sbDownloadDeviceHelper.prototype._setDownloadDestinationIfNotSet =
  396. function sbDownloadDeviceHelper__setDownloadDestinationIfNotSet(aItems,
  397.                                                                 aDownloadPath)
  398. {
  399.   for each (var item in aItems) {
  400.     try {
  401.       var curDestination = item.getProperty(SBProperties.destination);
  402.       if (!curDestination) {
  403.         
  404.         // Ensure all paths are lowercase for Windows.
  405.         // See bug #7178.
  406.         var actualDestination = aDownloadPath;
  407.         if(getPlatformString() == "Windows_NT") {
  408.           actualDestination = actualDestination.toLowerCase();
  409.         }
  410.         
  411.         item.setProperty(SBProperties.destination, actualDestination);
  412.       }
  413.     }
  414.     catch (e) {
  415.       // We're not allowed to set the download destination on remote media items
  416.       // so that call may fail. The remoteAPI should unwrap all items and lists
  417.       // *before* handing them to us, so throw the error with a slightly more
  418.       // helpful message.
  419.       throw new CE("Download destination could not be set on this media item:\n"
  420.                    + "  " + item + "\nIs it actually a remote media item?",
  421.                    e.result);
  422.     }
  423.   }
  424. }
  425.  
  426. function NSGetModule(compMgr, fileSpec) {
  427.   return XPCOMUtils.generateModule([sbDownloadDeviceHelper]);
  428. }
  429.